package com.zhijian.medical.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.text.csv.CsvData;
import cn.hutool.core.text.csv.CsvReader;
import cn.hutool.core.text.csv.CsvRow;
import cn.hutool.core.text.csv.CsvUtil;
import com.google.common.collect.Lists;
import com.zhijian.medical.config.Constants;
import com.zhijian.medical.dao.local.PcrMapper;
import com.zhijian.medical.entity.dto.*;
import com.zhijian.medical.entity.po.*;
import com.zhijian.medical.entity.vo.request.*;
import com.zhijian.medical.entity.vo.response.*;
import com.zhijian.medical.enums.*;
import com.zhijian.medical.holder.CurrentUserHolder;
import com.zhijian.medical.service.*;
import com.zhijian.medical.util.AssertUtil;
import com.zhijian.medical.util.JsonUtil;
import com.zhijian.medical.util.Page;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 实验流程业务处理层
 *
 * @author HCG
 * @version: 1.0
 * @date 2022-08-30 15:34:00
 */
@Slf4j
@Service
public class PcrServiceImpl implements PcrService {

    @Autowired
    private PcrMapper mapper;

    @Autowired
    private ExperimentProcessSampleService experimentProcessSampleService;

    @Autowired
    private ExperimentProcessSampleHstqService experimentProcessSampleHstqService;

    @Autowired
    private ExperimentProcessSampleReadyService experimentProcessSampleReadyService;

    @Autowired
    private PcrSjpzqService pcrSjpzqService;

    @Autowired
    private PcrHszbqService pcrHszbqService;

    @Autowired
    private PcrHskzyqService pcrHskzyqService;

    @Autowired
    private PcrYbzbService pcrYbzbService;

    @Autowired
    private PcrResultService pcrResultService;

    @Autowired
    private PcrResultDetailService pcrResultDetailService;

    @Autowired
    private ExperimentReportService experimentReportService;

    @Autowired
    private DeviceService deviceService;

    @Autowired
    private PcrKzyService pcrKzyService;

    @Autowired
    private ExperimentProcessSampleLogService experimentProcessSampleLogService;

    /**
     * 编号
     */
    private static final String number = "FZ-SOP-021-01-%s-%s";

    @Override
    public Pcr selectById(Long id) {
        return mapper.selectByPrimaryKey(id);
    }

    @Override
    public PcrVo selectVoById(Long id) {
        PcrVo sangerVo = mapper.selectVoById(id);
        if (Objects.isNull(sangerVo)) {
            return null;
        }
        sangerVo.setExperimentProcessSampleList(experimentProcessSampleService.selectList(ExperimentProcessSampleSearchVo.builder()
                .experimentProcessId(id)
                .mainType(ExperimentTypeEnum.PCR.getCode().byteValue())
                .build()));
        return sangerVo;
    }

    @Transactional(rollbackFor = Exception.class, value = "localTransactionManager")
    @Override
    public void deleteById(Long id) {
        pcrHskzyqService.deleteByPcrId(id);
        pcrHszbqService.deleteByPcrId(id);
        pcrKzyService.deleteByPcrId(id);
        pcrResultDetailService.deleteByPcrId(id);
        pcrResultService.deleteByPcrId(id);
        pcrSjpzqService.deleteByPcrId(id);
        pcrYbzbService.deleteByPcrId(id);
        mapper.deleteByPrimaryKey(id);
    }

    @Override
    public Long insert(Pcr pcr) {
        Date now = new Date();
        pcr.setCreateTime(now);
        pcr.setUpdateTime(now);
        return mapper.insert(pcr) > 0 ? pcr.getId() : 0L;
    }

    @Transactional(rollbackFor = Exception.class, value = "localTransactionManager")
    @Override
    public Long insert(PcrSaveOrUpdateVo pcrSaveOrUpdateVo) {
        Pcr pcr = new Pcr();
        BeanUtils.copyProperties(pcrSaveOrUpdateVo, pcr);
        Date now = new Date();
        String today = DateUtil.formatDate(now);
        pcr.setStartTime(now);
        pcr.setStatus(PcrKnbStatusEnum.YBZBQ.getCode().byteValue());
        //今天有几个实验了
        Integer count = this.count(PcrSearchVo.builder()
                .startDay(today)
                .build());
        String processNumber = String.format(number, DateUtil.format(now, "yyyyMMdd"), String.format("%02d", count + 1));
        //编号
        pcr.setProcessNumber(processNumber);
        Long experimentProcessId = this.insert(pcr);
        //类型
        Byte type = pcrSaveOrUpdateVo.getType();
        PcrTypeEnum pcrTypeEnum = PcrTypeEnum.getByCode(type.intValue());
        AssertUtil.notNull(pcrTypeEnum, "类型非法");
        assert pcrTypeEnum != null;
        switch (pcrTypeEnum) {
            case KNB:
                Byte result = saveKnbOtherData(experimentProcessId, pcrSaveOrUpdateVo.getName(), processNumber, pcrSaveOrUpdateVo.getSampleIds());
                if (Objects.nonNull(result)) {
                    //再把实验的状态改为真实的状态区域
                    this.updateByPrimaryKeySelective(Pcr.builder()
                            .id(experimentProcessId)
                            .status(result)
                            .build());
                }
                break;
            case GW_HPV:
                break;
            case FA_5:
                break;
            case JAK2:
                break;
            case PIK3CA:
                break;
            case COV:
                saveCovOtherData(experimentProcessId, pcrSaveOrUpdateVo.getName(), processNumber, pcrSaveOrUpdateVo.getSampleIds());
                //再把实验的状态改为新冠病毒的初始区域，试剂配置区
                this.updateByPrimaryKeySelective(Pcr.builder()
                        .id(experimentProcessId)
                        .status(PcrCovStatusEnum.SJPZQ.getCode().byteValue())
                        .build());
                break;
            default:
                break;
        }
        return experimentProcessId;
    }

    /**
     * 保存KNB其他数据
     *
     * @param pcrId
     * @param pcrName
     * @param processNumber
     * @param sampleIds
     */
    private Byte saveKnbOtherData(Long pcrId, String pcrName, String processNumber, List<Long> sampleIds) {

        //核酸提取记录id
        final Long[] hstqId = {null};
        //样本准备记录id
        final Long[] readyId = {null};

        //样本准备区检测项目数据
        List<PcrYbzbProjectDto> projectDataList = Lists.newArrayList();

        //样本日志数据
        List<ExperimentProcessSampleLog> experimentProcessSampleLogList = Lists.newArrayList();

        sampleIds.forEach(s -> {
            ExperimentProcessSample experimentProcessSample = experimentProcessSampleService.selectById(s);
            AssertUtil.notNull(experimentProcessSample, "有样本不存在或者已被删除");
            hstqId[0] = experimentProcessSample.getHtstqId();
            readyId[0] = experimentProcessSample.getReadyId();
            projectDataList.add(PcrYbzbProjectDto.builder()
                    .id(s)
                    .project(experimentProcessSample.getProject())
                    .fzblh(experimentProcessSample.getMoleculePathologyNumber())
                    .cgblh(experimentProcessSample.getConventionPathologyNumber())
                    .zlxbbl(experimentProcessSample.getZlxbbl())
                    .build());
            experimentProcessSampleService.updateByPrimaryKeySelective(ExperimentProcessSample.builder()
                    .id(s)
                    .experimentProcessId(pcrId)
                    //状态改为检测中
                    .status(PcrSampleStatusEnum.JCZ.getCode().byteValue())
                    .build());
            experimentProcessSampleLogList.add(ExperimentProcessSampleLog.builder()
                    .sampleId(s)
                    .fishId(pcrId)
                    .mainType(experimentProcessSample.getMainType())
                    .op(String.format("%s%s-待检测", pcrName, processNumber))
                    .opUser(CurrentUserHolder.getUser().getName())
                    .build());

        });

        Byte result = null;
        //样本准备区
        PcrYbzb pcrYbzb = new PcrYbzb();
        //如果之前做过样本准备，把一些数据同步过来
        if (Objects.nonNull(readyId[0])) {
            ExperimentProcessSampleReadyVo experimentProcessSampleReadyVo = experimentProcessSampleReadyService.selectVoById(readyId[0]);
            if (Objects.nonNull(experimentProcessSampleReadyVo)) {
                BeanUtils.copyProperties(experimentProcessSampleReadyVo, pcrYbzb);
                //结果是核酸制备区
                result = PcrKnbStatusEnum.HSZBQ.getCode().byteValue();
            }
        }
        pcrYbzb.setPcrId(pcrId);
        pcrYbzb.setProjectData(JsonUtil.toString(projectDataList));
        pcrYbzb.setJcrq(DateUtil.formatDate(new Date()));

        //核酸制备区
        PcrHszbq pcrHszbq = new PcrHszbq();
        pcrHszbq.setPcrId(pcrId);
        //如果之前做过核酸提取，把一些数据同步过来
        if (Objects.nonNull(hstqId[0])) {
            ExperimentProcessSampleHstqVo experimentProcessSampleHstqVo = experimentProcessSampleHstqService.selectVoById(hstqId[0]);
            if (Objects.nonNull(experimentProcessSampleHstqVo)) {
                pcrHszbq.setHszbqhstqsyqsystmqj(experimentProcessSampleHstqVo.getSyqsystmqj());
                pcrHszbq.setHszbqhstqhstqsjsjzyxqn(experimentProcessSampleHstqVo.getSjzyxqn());
                pcrHszbq.setHszbqhstqsjzzdgqjxhgcywyc(experimentProcessSampleHstqVo.getSjzzdgqjxhgczywyc());
                pcrHszbq.setHszbqhstqsjzzdgqjxhclfs(experimentProcessSampleHstqVo.getSjzzdgqjxhgczclfs());
                pcrHszbq.setHszbqhstqhstqgcgcywyc(experimentProcessSampleHstqVo.getHstqgcywyc());
                pcrHszbq.setHszbqhstqhstqgcclfs(experimentProcessSampleHstqVo.getHstqgcclfs());
                pcrHszbq.setHszbqhstqyqsbsyqktsgslxj(experimentProcessSampleHstqVo.getTsgsldlxj());
                pcrHszbq.setHszbqhstqyqsbsyqkzdq(experimentProcessSampleHstqVo.getZdq());
                pcrHszbq.setHszbqhstqyqsbsyqkswaqg(experimentProcessSampleHstqVo.getSwaqg());
                pcrHszbq.setHszbqhstqyqsbsyqkhwjsg(experimentProcessSampleHstqVo.getHwjsy());
                pcrHszbq.setHszbqhstqsyhqjjzwzssygztm(experimentProcessSampleHstqVo.getSyhqjjzwzssygztm());
                pcrHszbq.setHszbqhstqsyhjxsyqzwxzs(experimentProcessSampleHstqVo.getSyhjxsyqzwxzs());
                pcrHszbq.setHszbqhstqsyhclsyfqw(experimentProcessSampleHstqVo.getSyhclsyfqw());
                pcrHszbq.setFykData(experimentProcessSampleHstqVo.getFykData());
                //结果是试剂配置区
                result = PcrKnbStatusEnum.SJPZQ.getCode().byteValue();
            }
        }

        //试剂配置区
        PcrSjpzq pcrSjpzq = new PcrSjpzq();
        List<YgpcrSjpzqKnbSjDto> sjpzqSjDataList = Lists.newLinkedList();
        sjpzqSjDataList.add(YgpcrSjpzqKnbSjDto.builder()
                .project("KRAS/NRAS突变检测")
                .build());
        sjpzqSjDataList.add(YgpcrSjpzqKnbSjDto.builder()
                .project("BRAF突变检测")
                .build());
        pcrSjpzq.setSjpzqSjData(JsonUtil.toString(sjpzqSjDataList));
        pcrSjpzq.setPcrId(pcrId);

        //核酸扩增一区
        PcrHskzyq pcrHskzyq = new PcrHskzyq();
        pcrHskzyq.setPcrId(pcrId);

        pcrYbzbService.insert(pcrYbzb);
        pcrHszbqService.insert(pcrHszbq);
        pcrSjpzqService.insert(pcrSjpzq);
        pcrHskzyqService.insert(pcrHskzyq);
        return result;
    }

    /**
     * 保存新冠病毒其他数据
     *
     * @param pcrId
     * @param pcrName
     * @param processNumber
     * @param sampleIds
     */
    private void saveCovOtherData(Long pcrId, String pcrName, String processNumber, List<Long> sampleIds) {

        //核酸提取记录id
        final Long[] hstqId = {null};

        //样本准备区检测项目数据
        List<PcrYbzbProjectDto> projectDataList = Lists.newArrayList();

        //样本日志数据
        List<ExperimentProcessSampleLog> experimentProcessSampleLogList = Lists.newArrayList();

        sampleIds.forEach(s -> {
            ExperimentProcessSample experimentProcessSample = experimentProcessSampleService.selectById(s);
            AssertUtil.notNull(experimentProcessSample, "有样本不存在或者已被删除");
            hstqId[0] = experimentProcessSample.getHtstqId();
            projectDataList.add(PcrYbzbProjectDto.builder()
                    .id(s)
                    .project(experimentProcessSample.getProject())
                    .fzblh(experimentProcessSample.getMoleculePathologyNumber())
                    .cgblh(experimentProcessSample.getConventionPathologyNumber())
                    .zlxbbl(experimentProcessSample.getZlxbbl())
                    .build());
            experimentProcessSampleService.updateByPrimaryKeySelective(ExperimentProcessSample.builder()
                    .id(s)
                    .experimentProcessId(pcrId)
                    //状态改为检测中
                    .status(PcrSampleStatusEnum.JCZ.getCode().byteValue())
                    .build());
            experimentProcessSampleLogList.add(ExperimentProcessSampleLog.builder()
                    .sampleId(s)
                    .fishId(pcrId)
                    .mainType(experimentProcessSample.getMainType())
                    .op(String.format("%s%s-待检测", pcrName, processNumber))
                    .opUser(CurrentUserHolder.getUser().getName())
                    .build());

        });

        String fykData = null;

        //核酸制备区
        PcrHszbq pcrHszbq = new PcrHszbq();
        pcrHszbq.setPcrId(pcrId);
        //如果之前做过核酸提取，把一些数据同步过来
        if (Objects.nonNull(hstqId[0])) {
            ExperimentProcessSampleHstqVo experimentProcessSampleHstqVo = experimentProcessSampleHstqService.selectVoById(hstqId[0]);
            if (Objects.nonNull(experimentProcessSampleHstqVo)) {
                pcrHszbq.setHszbqhstqsyqsystmqj(experimentProcessSampleHstqVo.getSyqsystmqj());
                pcrHszbq.setHszbqhstqhstqsjsjzyxqn(experimentProcessSampleHstqVo.getSjzyxqn());
                pcrHszbq.setHszbqhstqsjzzdgqjxhgcywyc(experimentProcessSampleHstqVo.getSjzzdgqjxhgczywyc());
                pcrHszbq.setHszbqhstqsjzzdgqjxhclfs(experimentProcessSampleHstqVo.getSjzzdgqjxhgczclfs());
                pcrHszbq.setHszbqhstqhstqgcgcywyc(experimentProcessSampleHstqVo.getHstqgcywyc());
                pcrHszbq.setHszbqhstqhstqgcclfs(experimentProcessSampleHstqVo.getHstqgcclfs());
                pcrHszbq.setHszbqhstqyqsbsyqktsgslxj(experimentProcessSampleHstqVo.getTsgsldlxj());
                pcrHszbq.setHszbqhstqyqsbsyqkzdq(experimentProcessSampleHstqVo.getZdq());
                pcrHszbq.setHszbqhstqyqsbsyqkswaqg(experimentProcessSampleHstqVo.getSwaqg());
                pcrHszbq.setHszbqhstqyqsbsyqkhwjsg(experimentProcessSampleHstqVo.getHwjsy());
                pcrHszbq.setQzdhstqy(experimentProcessSampleHstqVo.getQzdhstqy());
                pcrHszbq.setHszbqhstqsyhqjjzwzssygztm(experimentProcessSampleHstqVo.getSyhqjjzwzssygztm());
                pcrHszbq.setHszbqhstqsyhjxsyqzwxzs(experimentProcessSampleHstqVo.getSyhjxsyqzwxzs());
                pcrHszbq.setHszbqhstqsyhclsyfqw(experimentProcessSampleHstqVo.getSyhclsyfqw());
                fykData = experimentProcessSampleHstqVo.getFykData();

                if (StringUtils.isNotBlank(fykData)) {
                    List<HstqOfHstqyVo> hstqOfHstqyVos = JsonUtil.toArray(fykData, HstqOfHstqyVo.class);
                    List<PcrHszbqFykDto> pcrHszbqFykDtos = hstqOfHstqyVos.stream().map(h -> {
                        PcrHszbqFykDto pcrHszbqFykDto = new PcrHszbqFykDto();
                        pcrHszbqFykDto.setPcrName(h.getDeviceName());
                        pcrHszbqFykDto.setData(h.getFykDataList());
                        return pcrHszbqFykDto;
                    }).collect(Collectors.toList());
                    pcrHszbq.setFykData(JsonUtil.toString(pcrHszbqFykDtos));
                }

            }
        }

        //试剂配置区
        PcrSjpzq pcrSjpzq = new PcrSjpzq();
        pcrSjpzq.setJcrq(DateUtil.formatDate(new Date()));
        List<YgpcrSjpzqCovSjDto> sjpzqSjDataList = Lists.newLinkedList();
        sjpzqSjDataList.add(YgpcrSjpzqCovSjDto.builder()
                .project("新冠")
                .build());
        pcrSjpzq.setSjpzqSjData(JsonUtil.toString(sjpzqSjDataList));
        pcrSjpzq.setPcrId(pcrId);

        //核酸扩增一区
        PcrHskzyq pcrHskzyq = new PcrHskzyq();
        pcrHskzyq.setPcrId(pcrId);

        pcrHszbqService.insert(pcrHszbq);
        pcrSjpzqService.insert(pcrSjpzq);
        pcrHskzyqService.insert(pcrHskzyq);

        //扩增仪列表
        List<Device> kzyList = deviceService.selectListByType(DeviceTypeEnum.KZY.getRealName());
        if (CollectionUtil.isNotEmpty(kzyList)) {
            List<HstqOfHstqyVo> hstqOfHstqyVos = JsonUtil.toArray(fykData, HstqOfHstqyVo.class);
            if (CollectionUtil.isNotEmpty(hstqOfHstqyVos)) {
                for (int i = 0; i < hstqOfHstqyVos.size() && i < kzyList.size(); i++) {
                    //默认取第一个扩增仪
                    Device firstKzy = kzyList.get(i);
                    PcrKzy pcrKzy = new PcrKzy();
                    pcrKzy.setPcrId(pcrId);
                    pcrKzy.setDeviceId(firstKzy.getId());
                    pcrKzy.setLcbbbshkzwzData(JsonUtil.toString(hstqOfHstqyVos.get(i).getFykDataList()));
                    pcrKzyService.insert(pcrKzy);
                }
            }
        }
    }

    @Override
    public boolean update(Pcr pcr) {
        Date now = new Date();
        pcr.setUpdateTime(now);
        return mapper.updateByPrimaryKey(pcr) != 0;
    }

    @Override
    public boolean update(PcrSaveOrUpdateVo pcrSaveOrUpdateVo) {
        Pcr oldPcr = this.selectById(pcrSaveOrUpdateVo.getId());
        AssertUtil.notNull(oldPcr, "此实验不存在或者已被删除");
        Pcr pcr = new Pcr();
        BeanUtils.copyProperties(pcrSaveOrUpdateVo, pcr);
        return this.updateByPrimaryKeySelective(pcr);
    }

    @Override
    public boolean updateByPrimaryKeySelective(Pcr record) {
        return mapper.updateByPrimaryKeySelective(record) != 0;
    }

    @Override
    public Integer count(PcrSearchVo pcrSearchVo) {
        return mapper.count(pcrSearchVo);
    }

    @Override
    public List<PcrVo> selectList(PcrSearchVo pcrSearchVo) {
        return mapper.selectList(pcrSearchVo);
    }

    @Override
    public Page<PcrVo> selectPage(PcrSearchVo pcrSearchVo) {
        //先直接查总数
        int count = count(pcrSearchVo);
        //分页
        Page<PcrVo> page = new Page<>(true, count, pcrSearchVo.getPageNum(), pcrSearchVo.getPageSize());
        pcrSearchVo.setStartIndex(page.getStartIndex());
        page.setPage(true);
        page.setTotalCount(count);
        List<PcrVo> responseVos = this.selectList(pcrSearchVo);
        page.setData(responseVos);
        return page;
    }

    @Override
    public ExperimentProcessSampleReadyVo selectReadyVoByPcrId(Long pcrId) {
        List<ExperimentProcessSampleVo> experimentProcessSampleVos = experimentProcessSampleService.selectList(ExperimentProcessSampleSearchVo.builder()
                .mainType(ExperimentTypeEnum.PCR.getCode().byteValue())
                .experimentProcessId(pcrId)
                .build());
        if (CollectionUtil.isEmpty(experimentProcessSampleVos)) {
            return null;
        }
        //样本准备id
        Long readyId = experimentProcessSampleVos.stream().filter(e -> Objects.nonNull(e.getReadyId())).map(ExperimentProcessSampleVo::getReadyId).findFirst().orElse(null);
        if (Objects.isNull(readyId)) {
            return null;
        }
        return experimentProcessSampleReadyService.selectVoById(readyId);
    }

    @Transactional(rollbackFor = Exception.class, value = "localTransactionManager")
    @Override
    public List<ExperimentProcessSampleVo> importCsv(Long pcrId, MultipartFile file) {
        InputStream inputStream = null;
        try {
            inputStream = file.getInputStream();
        } catch (IOException e) {
            e.printStackTrace();
        }
        CsvReader csvReader = CsvUtil.getReader();
        assert inputStream != null;
        CsvData read = csvReader.read(new InputStreamReader(inputStream, Charset.forName("UTF_16LE")));
        List<CsvRow> rows = read.getRows();

        for (int i = 1; i < rows.size(); i++) {
            List<String> rawList = rows.get(i).getRawList();
            if (CollectionUtils.isEmpty(rawList)) {
                continue;
            }
            String s = rawList.get(0);
            String[] split = s.split("\\t");
            if (split.length < 7) {
                continue;
            }
            String b = split[1];
            String c = split[2];
            String d = split[3];
            String e = split[4];
            if (StringUtils.isAllBlank(b, c, d, e)) {
                continue;
            }

            ExperimentProcessSample experimentProcessSample = experimentProcessSampleService.selectByFzblh(b);

            AssertUtil.check(Objects.isNull(experimentProcessSample) || Objects.isNull(experimentProcessSample.getExperimentProcessId()) || !Objects.equals(experimentProcessSample.getExperimentProcessId(), pcrId), String.format("分子病理号为'%s'的样本，不存在于此次试验，请检查后重新导入", b));

            experimentProcessSampleService.updateByPrimaryKeySelective(ExperimentProcessSample.builder()
                    .id(experimentProcessSample.getId())
                    .nd(c)
                    .od260280(new BigDecimal(d))
                    .od260230(new BigDecimal(e))
                    .build());
        }
        return experimentProcessSampleService.selectList(ExperimentProcessSampleSearchVo.builder()
                .experimentProcessId(pcrId)
                .mainType(ExperimentTypeEnum.PCR.getCode().byteValue())
                .build());
    }

    @Transactional(rollbackFor = Exception.class, value = "localTransactionManager")
    @Override
    public boolean createKnbReport(Long pcrId) {
        Pcr pcr = this.selectById(pcrId);
        AssertUtil.notNull(pcr, "此实验流程不存在或者已被删除");
        Date now = new Date();
        List<ExperimentProcessSampleVo> experimentProcessSampleVos = experimentProcessSampleService.selectList(ExperimentProcessSampleSearchVo.builder()
                .experimentProcessId(pcrId)
                .mainType(ExperimentTypeEnum.PCR.getCode().byteValue())
                .build());
        AssertUtil.notNull(CollectionUtil.isEmpty(experimentProcessSampleVos), "此实验流程无任何样本");
//        //分子病理号
//        List<String> moleculePathologyNumberList = experimentProcessSampleVos.stream().map(ExperimentProcessSampleVo::getMoleculePathologyNumber).distinct().collect(Collectors.toList());
//
//        List<PcrResultVo> pcrResultVos = pcrResultService.selectList(PcrResultSearchVo.builder()
//                .pcrId(pcrId)
//                .build());

//        //结果判定的病理号
//        List<String> blhList = pcrResultVos.stream().map(PcrResultVo::getBlh).distinct().collect(Collectors.toList());
//        blhList.remove(Constants.Pcr.NTC);
//        blhList.remove(Constants.Pcr.STD);
//        boolean equalCollection = org.apache.commons.collections4.CollectionUtils.isEqualCollection(moleculePathologyNumberList, blhList);
//        AssertUtil.check(!equalCollection, "实验结果与实验样本不匹配");

        //先把之前的删掉
        experimentReportService.deleteByTypeAndExperimentProcessId(ExperimentTypeEnum.PCR.getCode().byteValue(), pcrId);

        //样本日志数据
        List<ExperimentProcessSampleLog> experimentProcessSampleLogList = Lists.newArrayList();

        List<ExperimentReport> experimentReports = experimentProcessSampleVos.stream().map(experimentProcessSampleVo -> {
            ExperimentReport experimentReport = new ExperimentReport();
            experimentReport.setType(PcrTypeEnum.KNB.getCode().byteValue());
            experimentReport.setCreateTime(now);
            experimentReport.setUpdateTime(now);
            experimentReport.setExperimentProcessId(pcrId);
            experimentReport.setFzblh(experimentProcessSampleVo.getMoleculePathologyNumber());
            //项目，现在是多个了
            experimentReport.setProject(experimentProcessSampleVo.getProject());
            experimentReport.setJcxm(experimentProcessSampleVo.getProject());
            mergeToExperimentReportFromExperimentProcessSampleVo(experimentReport, experimentProcessSampleVo);
            experimentReport.setBblx(experimentProcessSampleVo.getType());
            //标本评估
            experimentReport.setBbpg("符合要求");

            //KRAS
            List<PcrResultVo> krasExperimentProcessResultVos = pcrResultService.selectList(PcrResultSearchVo.builder()
                    .pcrId(pcrId)
                    .project(ExperimentTypeEnum.PCR.getProject().get(0))
                    .blh(experimentProcessSampleVo.getMoleculePathologyNumber())
                    .build());
            if (CollectionUtil.isNotEmpty(krasExperimentProcessResultVos)) {
                PcrResultVo pcrResultVo = krasExperimentProcessResultVos.get(0);
                List<PcrResultDetailVo> experimentProcessResultDetailVos = pcrResultDetailService.selectList(PcrResultDetailSearchVo.builder()
                        .resultId(pcrResultVo.getId())
                        .build());
                if (CollectionUtil.isNotEmpty(experimentProcessResultDetailVos)) {
                    List<ExperimentReportJcxmDataDto> experimentReportJcxmDataDtos = experimentProcessResultDetailVos.stream().map(experimentProcessResultDetailVo -> {
                        ExperimentReportJcxmDataDto experimentReportJcxmDataDto = new ExperimentReportJcxmDataDto();
                        experimentReportJcxmDataDto.setJcxm(ExperimentTypeEnum.PCR.getProject().get(0));
                        experimentReportJcxmDataDto.setJcdw(experimentProcessResultDetailVo.getFyk());
                        experimentReportJcxmDataDto.setJgms(experimentProcessResultDetailVo.getYyx());
                        experimentReportJcxmDataDto.setCtz(Objects.nonNull(experimentProcessResultDetailVo.getNkct()) ? experimentProcessResultDetailVo.getNkct() + "" : "");
                        experimentReportJcxmDataDto.setDrtctz(Objects.nonNull(experimentProcessResultDetailVo.getCt3()) ? experimentProcessResultDetailVo.getCt3() + "" : "");
                        experimentReportJcxmDataDto.setJcjg(experimentProcessResultDetailVo.getYyx());
                        return experimentReportJcxmDataDto;
                    }).collect(Collectors.toList());
                    experimentReport.setKrasdata(JsonUtil.toString(experimentReportJcxmDataDtos));
                }
            }

            //NRAS
            List<PcrResultVo> nrasExperimentProcessResultVos = pcrResultService.selectList(PcrResultSearchVo.builder()
                    .pcrId(pcrId)
                    .project(ExperimentTypeEnum.PCR.getProject().get(1))
                    .blh(experimentProcessSampleVo.getMoleculePathologyNumber())
                    .build());
            if (CollectionUtil.isNotEmpty(nrasExperimentProcessResultVos)) {
                PcrResultVo pcrResultVo = nrasExperimentProcessResultVos.get(0);
                List<PcrResultDetailVo> experimentProcessResultDetailVos = pcrResultDetailService.selectList(PcrResultDetailSearchVo.builder()
                        .resultId(pcrResultVo.getId())
                        .build());
                if (CollectionUtil.isNotEmpty(experimentProcessResultDetailVos)) {
                    List<ExperimentReportJcxmDataDto> experimentReportJcxmDataDtos = experimentProcessResultDetailVos.stream().map(experimentProcessResultDetailVo -> {
                        ExperimentReportJcxmDataDto experimentReportJcxmDataDto = new ExperimentReportJcxmDataDto();
                        experimentReportJcxmDataDto.setJcxm(ExperimentTypeEnum.PCR.getProject().get(1));
                        experimentReportJcxmDataDto.setJcdw(experimentProcessResultDetailVo.getFyk());
                        experimentReportJcxmDataDto.setJgms(experimentProcessResultDetailVo.getYyx());
                        experimentReportJcxmDataDto.setCtz(Objects.nonNull(experimentProcessResultDetailVo.getNkct()) ? experimentProcessResultDetailVo.getNkct() + "" : "");
                        experimentReportJcxmDataDto.setDrtctz(Objects.nonNull(experimentProcessResultDetailVo.getCt3()) ? experimentProcessResultDetailVo.getCt3() + "" : "");
                        experimentReportJcxmDataDto.setJcjg(experimentProcessResultDetailVo.getYyx());
                        return experimentReportJcxmDataDto;
                    }).collect(Collectors.toList());
                    experimentReport.setNrasdata(JsonUtil.toString(experimentReportJcxmDataDtos));
                }
            }

            //BRAF
            List<PcrResultVo> brafExperimentProcessResultVos = pcrResultService.selectList(PcrResultSearchVo.builder()
                    .pcrId(pcrId)
                    .project(ExperimentTypeEnum.PCR.getProject().get(2))
                    .blh(experimentProcessSampleVo.getMoleculePathologyNumber())
                    .build());
            if (CollectionUtil.isNotEmpty(brafExperimentProcessResultVos)) {
                PcrResultVo pcrResultVo = brafExperimentProcessResultVos.get(0);
                List<PcrResultDetailVo> experimentProcessResultDetailVos = pcrResultDetailService.selectList(PcrResultDetailSearchVo.builder()
                        .resultId(pcrResultVo.getId())
                        .build());
                if (CollectionUtil.isNotEmpty(experimentProcessResultDetailVos)) {
                    List<ExperimentReportJcxmDataDto> experimentReportJcxmDataDtos = experimentProcessResultDetailVos.stream().map(experimentProcessResultDetailVo -> {
                        ExperimentReportJcxmDataDto experimentReportJcxmDataDto = new ExperimentReportJcxmDataDto();
                        experimentReportJcxmDataDto.setJcxm(ExperimentTypeEnum.PCR.getProject().get(2));
                        experimentReportJcxmDataDto.setJcdw(experimentProcessResultDetailVo.getFyk());
                        experimentReportJcxmDataDto.setJgms(experimentProcessResultDetailVo.getYyx());
                        experimentReportJcxmDataDto.setCtz(Objects.nonNull(experimentProcessResultDetailVo.getNkct()) ? experimentProcessResultDetailVo.getNkct() + "" : "");
                        experimentReportJcxmDataDto.setDrtctz(Objects.nonNull(experimentProcessResultDetailVo.getCt3()) ? experimentProcessResultDetailVo.getCt3() + "" : "");
                        experimentReportJcxmDataDto.setJcjg(experimentProcessResultDetailVo.getYyx());
                        return experimentReportJcxmDataDto;
                    }).collect(Collectors.toList());
                    experimentReport.setBrafdata(JsonUtil.toString(experimentReportJcxmDataDtos));
                }
            }

            experimentProcessSampleLogList.add(ExperimentProcessSampleLog.builder()
                    .sampleId(experimentProcessSampleVo.getId())
                    .fishId(pcrId)
                    .mainType(ExperimentTypeEnum.PCR.getCode().byteValue())
                    .op("检测结束，生成《KNB》实验报告")
                    .opUser(CurrentUserHolder.getUser().getName())
                    .build());
            return experimentReport;
        }).collect(Collectors.toList());
        experimentReportService.insertBatch(experimentReports);

        //保存样本日志
        if (CollectionUtil.isNotEmpty(experimentProcessSampleLogList)) {
            experimentProcessSampleLogService.saveBatch(experimentProcessSampleLogList);
        }
        return true;
    }

    @Transactional(rollbackFor = Exception.class, value = "localTransactionManager")
    @Override
    public boolean createCovReport(Long pcrId) {
        Pcr pcr = this.selectById(pcrId);
        AssertUtil.notNull(pcr, "此实验流程不存在或者已被删除");
        Date now = new Date();
        List<ExperimentProcessSampleVo> experimentProcessSampleVos = experimentProcessSampleService.selectList(ExperimentProcessSampleSearchVo.builder()
                .experimentProcessId(pcrId)
                .mainType(ExperimentTypeEnum.PCR.getCode().byteValue())
                .build());
        AssertUtil.notNull(CollectionUtil.isEmpty(experimentProcessSampleVos), "此实验流程无任何样本");

        List<PcrResultVo> pcrResultVoList = pcrResultService.selectList(PcrResultSearchVo.builder()
                .pcrId(pcrId)
                .build());
        AssertUtil.check(CollectionUtil.isEmpty(pcrResultVoList), "此实验还未进行结果判定");
        //先把之前的删掉
        experimentReportService.deleteByTypeAndExperimentProcessId(ExperimentTypeEnum.PCR.getCode().byteValue(), pcrId);

        //样本日志数据
        List<ExperimentProcessSampleLog> experimentProcessSampleLogList = Lists.newArrayList();

        List<ExperimentReport> experimentReports = pcrResultVoList.stream().map(p -> {
            String blh = p.getBlh();
            if (blh.equals(Constants.Pcr.STD) || blh.equals(Constants.Pcr.NTC)) {
                return null;
            }
            ExperimentProcessSampleVo experimentProcessSampleVo = experimentProcessSampleVos.stream().filter(e -> e.getMoleculePathologyNumber().equals(blh)).findFirst().orElse(null);
            AssertUtil.check(Objects.isNull(experimentProcessSampleVo), String.format("分子病理号为%s的样本，不存在于此次实验中", blh));

            experimentProcessSampleLogList.add(ExperimentProcessSampleLog.builder()
                    .sampleId(experimentProcessSampleVo.getId())
                    .fishId(pcrId)
                    .mainType(ExperimentTypeEnum.PCR.getCode().byteValue())
                    .op("检测结束，生成《新冠病毒》实验报告")
                    .opUser(CurrentUserHolder.getUser().getName())
                    .build());
            ExperimentReport experimentReport = new ExperimentReport();
            experimentReport.setType(PcrTypeEnum.COV.getCode().byteValue());
            experimentReport.setCreateTime(now);
            experimentReport.setUpdateTime(now);
            experimentReport.setExperimentProcessId(pcrId);
            experimentReport.setFzblh(blh);
            experimentReport.setSampleId(experimentProcessSampleVo.getId());
            //项目就是新冠病毒
            experimentReport.setProject(ExperimentTypeEnum.PCR.getProject().get(7));
            mergeToExperimentReportFromExperimentProcessSampleVo(experimentReport, experimentProcessSampleVo);
            List<PcrResultDetailVo> pcrResultDetailVos = pcrResultDetailService.selectList(PcrResultDetailSearchVo.builder()
                    .resultId(p.getId())
                    .build());
            experimentReport.setJgms(CollectionUtil.isNotEmpty(pcrResultDetailVos) ? pcrResultDetailVos.get(0).getYyx() : "未检出");
            experimentReport.setJcjg(CollectionUtil.isNotEmpty(pcrResultDetailVos) ? pcrResultDetailVos.get(0).getYyx() : "未检出");
            return experimentReport;
        }).collect(Collectors.toList());
        if (CollectionUtil.isNotEmpty(experimentReports)) {
            experimentReportService.insertBatch(experimentReports.stream().filter(Objects::nonNull).collect(Collectors.toList()));
            //保存样本日志
            experimentProcessSampleLogService.saveBatch(experimentProcessSampleLogList);
        }
        return true;
    }

    /**
     * 把样本管理的数据复制到报告里
     *
     * @param target
     * @param source
     */
    private void mergeToExperimentReportFromExperimentProcessSampleVo(ExperimentReport target, ExperimentProcessSampleVo source) {
        target.setName(source.getName());
        target.setSex(source.getSex());
        target.setReceiveDate(DateUtil.parse(source.getReceiveDate(), new SimpleDateFormat("yyyy-MM-dd HH:mm")));
        target.setHospital(source.getHospital());
        target.setInfectedPatch(source.getInfectedPatch());
        target.setKb(source.getKb());
        target.setDoctor(source.getDoctor());
        target.setMzh(source.getMzh());
        target.setCh(source.getCh());
        target.setZyh(source.getZyh());
        target.setBlh(source.getConventionPathologyNumber());
        target.setAge(source.getAge());
    }

}